package com.gframework.mybatis.dao.mybatis.provider.per;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.builder.annotation.ProviderContext;
import org.apache.ibatis.jdbc.SQL;
import org.apache.ibatis.reflection.MetaObject;

import com.gframework.mybatis.config.MybatisConfig;
import com.gframework.mybatis.dao.ITableBasicDAO;
import com.gframework.mybatis.dao.mybatis.provider.MybatisDaoInfo;
import com.gframework.mybatis.dao.mybatis.provider.PojoInfo;
import com.gframework.mybatis.dao.mybatis.provider.core.ProviderPlusLanguageDriver;
import com.gframework.sqlparam.BeanSqlParam;
import com.gframework.sqlparam.MybatisParamNameCacheGenerator;
import com.gframework.sqlparam.NameGenerator;
import com.gframework.sqlparam.SqlParam;

/**
 * {@link ITableBasicDAO} 接口的sql提供类.<br>
 * 
 * @since 1.0.0
 * @author Ghwolf
 * 
 * @see ITableBasicDAO
 * @see ProviderPlusLanguageDriver
 */
public class TableBasicDaoProvider extends AbstractProvider{
	
	/**
	 * 保存一条数据，只会保存非null属性内容(自动增长列除外).
	 * @see ITableBasicDAO#save(Serializable)
	 */
	public static String save(Serializable vo, ProviderContext context){
		
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		
		SQL sql = new SQL().INSERT_INTO(pojo.getTableName());
		
		MetaObject m = MybatisConfig.newMetaObject(vo);
		String[] cs = pojo.getColumNames();
		String[] fs = pojo.getFieldNames();
		String[] pfs = pojo.getDynamicParamFieldNames();
		Map<String,Object> param = new HashMap<>(cs.length);
		for (int x = 0 ; x < cs.length ; x ++) {
			String f = fs[x];
			Object value = m.getValue(f);
			if (value == null) {
				continue ;
			}
			String c = cs[x];
			sql.VALUES(c,pfs[x]);
			param.put(c, value);
		}
		
		ProviderPlusLanguageDriver.setParam(param);
		return sql.toString();
	}
	
	/**
	 * 保存一条数据，会保存所有属性内容(自动增长列除外).
	 * @see ITableBasicDAO#saveAllColumn(Serializable)
	 */
	public static String saveAllColumn(Serializable vo,ProviderContext context) {
		
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		
		return new SQL()
				.INSERT_INTO(pojo.getTableName())
				.INTO_COLUMNS(pojo.getColumNames())
				.INTO_VALUES(pojo.getDynamicParamFieldNames())
				.toString();
	}
	
	/**
	 * 批量添加数据，只会保存非null属性内容(自动增长列除外).
	 * 忽略集合中的null对象
	 * @see ITableBasicDAO#saveBatch(Collection)
	 */
	public static String saveBatch(@Param("vos") Collection<? extends Serializable> vos,ProviderContext context) {
		return saveBatchSqlHandle(vos,context,false);
	}
	
	/**
	 * 批量添加数据，会保存所有属性内容(自动增长列除外).
	 * @see ITableBasicDAO#saveBatchAllColumn(Collection)
	 */
	public static String saveBatchAllColumn(@Param("vos") Collection<? extends Serializable> vos,ProviderContext context) {
		return saveBatchSqlHandle(vos,context,true);
	}
	
	/**
	 * 根据自定义条件更新(除主键之外的)非null属性字段.
	 */
	public static String update(BeanSqlParam<? extends Serializable> param,ProviderContext context) {
		
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();

		SQL sql = new SQL().UPDATE(pojo.getTableName());
		
		MetaObject m = MybatisConfig.newMetaObject(param.getPojo());
		
		String[] cs = pojo.getColumNames();
		String[] fs = pojo.getFieldNames();
		Map<String,Object> p = new HashMap<>(cs.length + param.getParamSize());
		for (int x = 0 ; x < cs.length ; x ++) {
			String fieldName = fs[x];
			Object value = m.getValue(fieldName);
			if (value != null) {
				sql.SET(cs[x] + " = #{" + fieldName + "}");
				p.put(fieldName,value);
			}
		}
		
		setSqlParam(param, sql, p);

		ProviderPlusLanguageDriver.setParam(p);
		return sql.toString();
	}
	
	/**
	 * 根据自定义条件更新(除主键之外的)全部属性字段.
	 */
	public static String updateAllColumn(BeanSqlParam<? extends Serializable> param,ProviderContext context) {
		
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();

		SQL sql = new SQL().UPDATE(pojo.getTableName());
		
		MetaObject m = MybatisConfig.newMetaObject(param.getPojo());
		
		String[] cs = pojo.getColumNames();
		String[] fs = pojo.getFieldNames();
		Map<String,Object> p = new HashMap<>(cs.length + param.getParamSize());
		for (int x = 0 ; x < cs.length ; x ++) {
			String fieldName = fs[x];
			sql.SET(cs[x] + " = #{" + fieldName + "}");
			p.put(fieldName,m.getValue(fieldName));
		}
		
		setSqlParam(param, sql, p);

		ProviderPlusLanguageDriver.setParam(p);
		return sql.toString();
	}
	
	/**
	 * 根据自定义条件删除（真实删除）数据.
	 */
	public static String delete(SqlParam param,ProviderContext context) {
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		
		SQL sql = new SQL().DELETE_FROM(pojo.getTableName());
		Map<String,Object> map = setSqlParam(param, sql);
		
		if (map != null && !map.isEmpty()) {
			ProviderPlusLanguageDriver.setParam(map);
		}
		
		return sql.toString();
	}
	
	/**
	 * 生成批量添加操作的sql语句
	 * @param allColumn 是否保存所有列，false表示只保存非null列
	 */
	private static String saveBatchSqlHandle(Collection<? extends Serializable> vos,ProviderContext context,boolean allColumn) {
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		NameGenerator ng = new MybatisParamNameCacheGenerator();
		
		SQL sql = new SQL()
				.INSERT_INTO(pojo.getTableName())
				.INTO_COLUMNS(pojo.getColumNames());
		String[] fs = pojo.getFieldNames();
		String[] values = new String[fs.length];
		Map<String,Object> param = new HashMap<>(vos.size() * fs.length);
		
		for (Serializable vo : vos) {
			if (vo == null) continue ;
			
			MetaObject m = MybatisConfig.newMetaObject(vo);
			for (int x = 0 ; x < fs.length ; x ++) {
				Object value = m.getValue(fs[x]);
				if (allColumn || value != null) {
					String name = ng.next();
					values[x] = "#{" + name + "}" ;
					param.put(name, value);
				} else {
					values[x] = "DEFAULT";
				}
			}
			
			sql.INTO_VALUES(values).ADD_ROW();
		}

		ProviderPlusLanguageDriver.setParam(param);
		return sql.toString();
	}

}

